使用 Git 脚本接口
CODESYS Git 为 Git 提供脚本接口。如何使用该接口的示例如下所示。在下面,您还将找到有关许多 Git 操作生成的消息的基于文本的输出
有关更多信息,请参阅: 脚本引擎 API 文档
要求
要运行以下示例,需要满足以下条件:
CODESYS 3.5.19.30 或更高版本
还需要以下组件:
CODESYS Library Documentation Support (创建编译后的库)
CODESYS Git 1.6.0.0 或更高版本
本地 Git 安装
重要
尽可能使用 SecureString 密码
为了提高安全性,应将密码作为.NET 安全字符串传递。
受影响的 GIT 操作有: clone
, fetch
, pull
, push
可以在 IronPython 中按如下方式创建 SecureStrings。“密码” 本身应该来自一个安全的字符串,而不是像这里的演示那样,在脚本中使用纯文本。在内部,提供的每个密码都经过安全处理
from System.Security import SecureString sec_str_password = SecureString() for c in "Passwort": sec_str_password.AppendChar(c)
为了在使用时采取进一步的安全措施 CODESYS Git 参见: CODESYS Git 的安全性
准备
CODESYS 图书馆
因为不是 CODESYS 库目前在 Git 中管理,源代码是 CODESYS 图书馆是必需的。这个 String Functions.library
来自的图书馆 CODESYS String Libraries 示例中使用了产品。
远程 Git 存储库
在本示例中,文件系统中的裸露的 Git 存储库用作远程存储库。
要做好准备,请先删除相应的目录,然后创建一个新目录。
import shutil import os def prepare_empty_dir(empty_dir_path): print("Prepare empty directory at", empty_dir_path) shutil.rmtree(empty_dir_path, ignore_errors=True) if not(os.path.exists(empty_dir_path) and os.path.isdir(empty_dir_path)): os.makedirs(empty_dir_path)
然后创建一个空的裸露的 Git 存储库。
import subprocess def create_bare_git_repository(bare_repository_path): print("Create bare git repository at", bare_repository_path) create_bare_repository_cmd = 'cmd /c "git -C \"' + bare_repository_path + '\" init --bare"' try: retcode = subprocess.call(create_bare_repository_cmd, shell=True) if retcode < 0: raise Exception("Creating bare git repository at " + bare_repository_path + " failed: ", -retcode) else: print("Creating bare git repository at " + bare_repository_path + " succeeded.") except Exception as e: print("[ERROR] Creating bare git repository failed: ", e) raise
空的裸露的 Git 存储库中充斥着的内容 CODESYS 图书馆。
def initialize_bare_git_repository(library_path, local_repository_path, bare_repository_path): print("Open library:", library_path) project = projects.open(library_path) print("Initiate local git repository") project.git.init(local_repository_path) project.git.commit_complete("Create git repo for lib", "user", "mail@mail") print("Push to remote git repository") origin_remote = project.git.remote_add("origin", bare_repository_path) project.git.branch_set_upstream_to(origin_remote) project.git.push() project.git.de_init(cleanUpFileSystem=True) project.close()
以下脚本执行所描述的函数。
import os def main(): if projects.primary: projects.primary.close() basepath = "C:\\CODESYS_Projects\\Git_Scripting_Tutorial\\" project_basepath = os.path.join(basepath, "projects\\") library_file_name = "ExampleLib1.library" library_path = os.path.join(project_basepath, library_file_name) remote_repo_basepath = os.path.join(basepath, "remotes\\") remote_repo_directory_name = "ExampleLib1RemoteRepo" remote_repo_path = os.path.join(remote_repo_basepath, remote_repo_directory_name) local_repo_basepath = os.path.join(basepath, "repos\\") local_repo_directory_name = "ExampleLib1LocalRepo" local_repo_path = os.path.join(local_repo_basepath, local_repo_directory_name) print("Create and push library to remote git repository") prepare_empty_dir(remote_repo_path) create_bare_git_repository(remote_repo_path) initialize_bare_git_repository(library_path, local_repo_path, remote_repo_path) print("[Success] All done") if __name__ == '__main__': main()
以这种方式创建并提供内容的裸露的 Git 存储库用于其他示例。
克隆远程 Git 存储库
执行以下函数 git clone
用于远程 Git 存储库。
def clone_git_repository(project_basepath, project_file_name, remote_repo_url_or_path, local_repo_path): update_flags = VersionUpdateFlags.UpdateAll | VersionUpdateFlags.SilentMode project = git.clone(project_basepath, project_file_name, remote_repo_url_or_path, local_repo_path, update_flags=update_flags) project.save() return project
创建和合并新分支
以下辅助函数在 a 中创建了一些新对象 CODESYS 以项目为例。
def add_dut(project): ST_STRUCT_STR = """\ a : BOOL; b : BIT; c : BIT; """ ST_UNION_STR = """\ TYPE ExampleUnion : UNION Zahl : INT; Prozent : ExampleAlias; Bits : ExampleStruct; END_UNION END_TYPE """ # Create a struct DUT and insert the list of variables just into the right # place in line two, row 0 (line numbering starts with line 0) example_dut_struct = project.create_dut('ExampleStruct') # DutType.Structure is the default example_dut_struct.textual_declaration.insert(2, 0, ST_STRUCT_STR) # Alias types get their "content" via the base type, which will just end up # as one line in the declaration part: # TYPE MyAlias : INT (0..100); END_TYPE example_dut_alias = project.create_dut('ExampleAlias', DutType.Alias, "INT (0..100)") # Instead of injecting the variables into the existing declaration, # one can also just replace the complete declaration part, including the # boilerplate code. example_dut_union = project.create_dut('ExampleUnion', DutType.Union) example_dut_union.textual_declaration.replace(ST_UNION_STR)
以下辅助函数递增项目信息中的编译版本 CODESYS 项目。
def increment_build_version(project): """ Increment build version in project info. """ info = project.get_project_info() old_version = info.version info.version = (old_version.Major, old_version.Minor, old_version.Build + 1, 0) project.save()
以下函数首先创建一个新分支并在该分支中进行更改,然后将这些更改合并回主分支。
def copy_branch_and_merge(project): current_branch = project.git.branch_show_current() print("Current branch: ", current_branch.friendly_name) project, current_branch = project.git.branch_copy(current_branch, "new_branch", checkout=True) print("Current branch: ", current_branch.friendly_name) add_dut(project) project.git.commit_complete("Added DUT", "user", "mail@mail") increment_build_version(project) project.git.commit_complete("Incremented build version", "user", "mail@mail") project, current_branch = project.git.checkout("master") print("Current branch: ", current_branch.friendly_name) project, merge_result = project.git.merge("new_branch") print("Merged: ", merge_result.ToString()) project.save() return project
以下脚本将执行 git clone
对于远程 Git 存储库,在项目中进行更改,然后将更改推送到远程 Git 存储库 (CopyBranchAndMerge.py)。
def main(): if projects.primary: projects.primary.close() basepath = "C:\\CODESYS_Projects\\Git_Scripting_Tutorial\\" project_basepath = os.path.join(basepath, "projects\\") library_file_name = "ExampleLib1Cloned.library" remote_repo_basepath = os.path.join(basepath, "remotes\\") remote_repo_directory_name = "ExampleLib1RemoteRepo" remote_repo_path = os.path.join(remote_repo_basepath, remote_repo_directory_name) local_repo_basepath = os.path.join(basepath, "repos\\") local_repo_directory_name = "ExampleLib1LocalRepo" local_repo_path = os.path.join(local_repo_basepath, local_repo_directory_name) print("Clone project") project = clone_git_repository(project_basepath, library_file_name, remote_repo_path, local_repo_path) project = copy_branch_and_merge(project) project.git.push() project.save() project.git.de_init(cleanUpFileSystem=True) project.save() project.close() print("[Success] All done") if __name__ == '__main__': main())
创建编译后的库
以下脚本将执行 git clone
对于 CODESYS 来自远程 Git 存储库的源库,然后从中创建编译后的库 (CreateCompiledLibrary.py)。
import os class CompileError(Exception): pass def clone_git_repository(project_basepath, project_file_name, remote_repo_url_or_path, local_repo_path): update_flags = VersionUpdateFlags.UpdateAll | VersionUpdateFlags.SilentMode project = git.clone(project_basepath, project_file_name, remote_repo_url_or_path, local_repo_path, update_flags=update_flags) project.save() return project def create_compiled_library(project): # requires the CODESYS Library Documentation Support Package! project.check_all_pool_objects() compile_result_message = system.get_messages(category='{97F48D64-A2A3-4856-B640-75C046E37EA9}')[-1] if "0 errors" in compile_result_message: project.save_as_compiled_library(destination_name=None) else: raise CompileError("Compile failed: " + compile_result_message) return project basepath = "D:\\JiraTickets\\GIT-145\\" project_basepath = os.path.join(basepath, "projects\\") remote_repo_basepath = os.path.join(basepath, "remotes\\") remote_repo_directory_name = "StringFunctions.git" remote_repo_path = os.path.join(remote_repo_basepath, remote_repo_directory_name) local_repo_basepath = os.path.join(basepath, "repos\\") local_repo_path = os.path.join(local_repo_basepath, "StringFunctions.git") print("Clone project") project = clone_git_repository(project_basepath, "String Functions Cloned.library", remote_repo_path, local_repo_path) project = create_compiled_library(project) project.git.de_init(cleanUpFileSystem=True) project.close() print("[Success] All done")
从远程 Git 存储库安装库
以下脚本将执行 git clone
对于 CODESYS 来自远程 Git 存储库的源库,并将此库安装在当前 Git 存储库中 CODESYS 实例(InstallLibrary.py)。
import os def clone_git_repository(project_directory_path, project_file_name, remote_repo_url_or_path, local_repo_path): update_flags = VersionUpdateFlags.UpdateAll | VersionUpdateFlags.SilentMode project = git.clone(project_directory_path, project_file_name, remote_repo_url_or_path, local_repo_path, update_flags=update_flags) project.save() return project def install_library(project): library_repo = librarymanager.repositories[0] librarymanager.install_library(project.path, library_repo, True) def main(): if projects.primary: projects.primary.close() basepath = "C:\\CODESYS_Projects\\Git_Scripting_Tutorial\\" project_basepath = os.path.join(basepath, "projects\\") library_file_name = "ExampleLib1Cloned2.library" remote_repo_basepath = os.path.join(basepath, "remotes\\") remote_repo_directory_name = "ExampleLib1RemoteRepo" remote_repo_path = os.path.join(remote_repo_basepath, remote_repo_directory_name) local_repo_basepath = os.path.join(basepath, "repos\\") local_repo_directory_name = "ExampleLib1LocalRepo" local_repo_path = os.path.join(local_repo_basepath, local_repo_directory_name) print("Clone project") project = clone_git_repository(project_basepath, library_file_name, remote_repo_path, local_repo_path) print("Install library") install_library(project) project.git.de_init(cleanUpFileSystem=True) project.close() print("[Success] All done") if __name__ == '__main__': main()
Git 操作的消息输出
使用时 CODESYS Git,大多数命令提供基于文本的输出。跑步时 CODESYS 在命令行中,这是在执行期间自动输出的输出 CODESYS Git 通过脚本驱动程序执行命令。使用时 CODESYS Git 在 CODESYS Development System,输出也会出现在消息窗口中。
Structure of the messages: Git:<severity>: [<time>] <text>
In the user interface of CODESYS Git, the output is reduced to: [<time>] <text>
severity
: 消息类别。类别从纯粹的信息错误到严重time
: 发送消息的确切时间。格式:HH:MM:SS
text
:消息的内容。对于标准 Git 命令,其内容对应于命令行命令,该命令将提供与脚本驱动程序调用相同的结果。对于 CODESYS Git 与标准 Git 命令不对应的命令(例如, 从存储库中恢复项目),消息文本解释了所执行的操作。
Commands with multiple messages:
对于某些命令(例如 git log
),输出被拆分为多条消息。就以下情况而言 git log
,每个显示的提交都显示在单独的消息中。在这种情况下,为了明确这些消息是其中的一部分 git log
命令,消息中引用了原始命令。